package com.xazenith.app;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * zip 压缩工具
 *
 * @author zhou wei
 * @version 0.1
 * @since 2020-11-12
 */
public class Zipper {

    private final static Logger logger = Logger.getLogger("Zipper");

    private final File source;

    private final String basePath;

    private final String rootFolderName;

    public Zipper(File source) {
        if (Objects.isNull(source)) {
            throw new IllegalArgumentException("source file could not be null! ");
        }
        if (!source.exists()) {
            throw new IllegalArgumentException("source file: " + source.getAbsolutePath() + " , could not be not exists! ");
        }
        this.source = source;
        this.basePath = this.source.getPath();
        this.rootFolderName = this.source.getName();
    }

    public ZipOutputStream zip(OutputStream ot) throws IOException {
        ZipOutputStream os = new ZipOutputStream(ot);
        zipInto(os, this.source);
        os.finish();
        os.flush();
        return os;
    }

    private void zipInto(ZipOutputStream os, File file) {
        if (file.isFile()) {
            if (file.isHidden()) {
                return;
            }
            try {
                byte[] bytes = FileUtils.readFileToByteArray(file);
                String name = replacePathAsRelative(file.getPath());
                os.putNextEntry(new ZipEntry(name));
                IOUtils.write(bytes, os);
            } catch (IOException ex) {
                String msg = "could not add ZIP entry, path: " + file.getPath()
                        + ", cause: " + ex.getCause() + ", message: " + ex.getMessage();
                byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
                logger.warning(new String(msgBytes, Charset.defaultCharset()));
            }
        }
        if (file.isDirectory()) {
            try {
                String name = replacePathAsRelative(file.getPath()) + "/";
                ZipEntry ett = new ZipEntry(name);
                os.putNextEntry(ett);
                File[] files = file.listFiles();
                if (Objects.nonNull(files)) {
                    for (File f : files) {
                        zipInto(os, f);
                    }
                }
            } catch (IOException ex) {
                String msg = "could not add folder ZIP entry, path: " + file.getPath()
                        + ", cause: " + ex.getCause() + ", message: " + ex.getMessage();
                byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
                logger.warning(new String(msgBytes, Charset.defaultCharset()));
            }
        }
    }

    private String replacePathAsRelative(String path) {
        String s = path.replace(this.basePath, "");
        if (s.isEmpty()) {
            return this.rootFolderName;
        }
        return this.rootFolderName + s;
    }
}
